#include "mtrap.h"
#include "riscv.h"
#include "htif.h"
#include "proc.h"
#include <stdio.h>
#include "trap.h"
#include "functions.h"
#include "finisher.h"
#include "console.h"

void hls_printm(hls_t * hls){
  printm("hls %p\n",hls);
  printm("  ipi %p\n",hls->ipi);
  printm("  mipi_penging %p\n",hls->mipi_pending);
  printm("  timecmp %p\n",hls->timecmp);
  printm("  plic_m_thresh %p\n",hls->plic_m_thresh);
  printm("  plic_m_ie %p\n",hls->plic_m_ie);
  printm("  plic_s_thresh %p\n",hls->plic_s_thresh);
  printm("  ipi %p\n",hls->plic_s_ie);
}

void hls_printk(hls_t * hls){
  printk("hls %p\n",hls);
  printk("  ipi %p\n",hls->ipi);
  printk("  mipi_penging %p\n",hls->mipi_pending);
  printk("  timecmp %p\n",hls->timecmp);
  printk("  plic_m_thresh %p\n",hls->plic_m_thresh);
  printk("  plic_m_ie %p\n",hls->plic_m_ie);
  printk("  plic_s_thresh %p\n",hls->plic_s_thresh);
  printk("  ipi %p\n",hls->plic_s_ie);
}

static uintptr_t mcall_console_putchar(uint8 ch)
{
 if (htif) {
    htif_console_putchar(ch);
  }
  return 0;
}

void putstring(const char* s)
{
  while (*s)
    mcall_console_putchar(*s++);
}


void vprintm(const char* s, va_list vl)
{
  char buf[256];
  vsnprintf(buf, sizeof buf, s, vl);
  putstring(buf);
}

void printm(const char* s, ...)
{
  va_list vl;

  va_start(vl, s);
  vprintm(s, vl);
  va_end(vl);
}


void poweroff(uint16_t code)
{
  assert(htif); 
  printm("Power off\r\n");
  finisher_exit(code);
  if (htif) {
    htif_poweroff();
  }else {
    //  send_ipi_many(0, IPI_HALT);
    while (1) { asm volatile ("wfi\n"); }
  }
   
}
static void handle_instruction_access_fault(struct trapframe *tf)
{
  dump_tf(tf);
  panic("Instruction access fault!");
}


static void handle_load_access_fault(struct trapframe *tf)
{
  dump_tf(tf);
  panic("Load access fault!");
}

static void handle_store_access_fault(struct trapframe *tf)
{
  dump_tf(tf);
  panic("Store/AMO access fault!");
}


static void handle_illegal_instruction(struct trapframe* tf)
{
//  your code here:
//  读取tf->epc
//  根据tf->epc得到tf->insn
//  打印tf
//  修改panic
	panic("you need add your code!");
}


static void handle_misaligned_load(struct trapframe* tf)
{
  dump_tf(tf);
  panic("Misaligned Load!");
}

static void handle_misaligned_store(struct trapframe* tf)
{
  dump_tf(tf);
  panic("Misaligned AMO!");
}

volatile size_t ticks;
static uint64 time_interval = 1e7 / 100;
static uint64 timebase = 1e7 / 100 ;


static void prvSetNextTimerInterrupt(void)
{
    volatile uint64 * timecmp=  HLS()->timecmp;
    timer_print();
    if (mtime && timecmp) 
        *timecmp = *mtime + time_interval;
    timer_print();
}
/*-----------------------------------------------------------*/

/* Sets and enable the timer interrupt */
void vPortSetupTimer(void)
{
    printm("set up timmer\n");
    /* reuse existing routine */
    prvSetNextTimerInterrupt();

	/* Enable timer interupt */
	__asm volatile("csrs sie,%0"::"r"(MIP_STIP));
}

static void handle_interrupt(struct trapframe* tf)
{
   
//   extern volatile size_t ticks;
//   printk("tf->cause %x\n",(intptr_t)tf->cause);
//   intptr_t cause = (read_csr(mcause) << 1) >> 1;
//   if(cause==IRQ_M_TIMER){
//     prvSetNextTimerInterrupt();
//     set_csr(sip,MIP_SSIP);
//   }
  
}
void handle_mtrap(struct trapframe* tf)
{

  typedef void (*trap_handler)(struct trapframe*);
    const static trap_handler trap_handlers[] = {
    [CAUSE_FETCH_ACCESS] = handle_instruction_access_fault,
    [CAUSE_LOAD_ACCESS] = handle_load_access_fault,
    [CAUSE_STORE_ACCESS] = handle_store_access_fault,
    [CAUSE_ILLEGAL_INSTRUCTION] = handle_illegal_instruction,
    [CAUSE_MISALIGNED_LOAD] = handle_misaligned_load,
    [CAUSE_MISALIGNED_STORE] = handle_misaligned_store,
  };
  ssize_t mcause=read_csr(mcause);
  printm("mcause %d\n",mcause);

  if (mcause < 0){
    handle_interrupt(tf);    
    return ;
  }else if( mcause < ARRAY_SIZE(trap_handlers) )
  {
      trap_handlers[mcause](tf);
  }else
  {
    printm("machine trap(): unexpected mscause %p pid=%d\n", mcause, myproc()->pid);
    printm("            mepc=%p mtval=%p\n", read_csr(mepc), read_csr(mtval));
  }
  
}

void mtrapret();
void mtrap(struct trapframe * tf){
    handle_mtrap(tf);
    mtrapret(tf);
}
